﻿namespace DomainServices.Tools
{
    using Microsoft.Build.Framework;
    using Microsoft.Build.Utilities;
    using System;
    using System.Collections.Generic;
    using System.Globalization;
    using System.IO;
    using System.Runtime.CompilerServices;
    using System.Linq;

    public abstract class RiaClientFilesTask : Task, ILoggingService, DomainServices.Tools.ILogger
    {
        private string _clientProjectDirectory;
        private bool _errorLogged;
        private bool _filesWritten;
        private string _generatedCodePath;
        private string _outputDirectory;
        internal const string ClientReferenceListFileName = "RiaClientRefs.txt";
        internal const string FileListFileName = "RiaFiles.txt";
        internal const string GeneratedCodeFolderName = "Generated_Code";
        internal const string LinkedServerProjectsFileName = "RiaLinks.txt";
        internal const string ServerReferenceListFileName = "RiaServerRefs.txt";
        internal const string SourceFileListFileName = "RiaSourceFiles.txt";

        protected RiaClientFilesTask()
        {
        }

        internal string ClientReferenceListPath()
        {
            return Path.Combine(this.GetHistoryFolder(), this.PrependClientProjectName("RiaClientRefs.txt"));
        }

        protected void DeleteCodeGenMetafileLists()
        {
            string str = this.FileListPath();
            if (!string.IsNullOrEmpty(str) && File.Exists(str))
            {
                this.SafeFileDelete(str);
            }
            str = this.ClientReferenceListPath();
            if (!string.IsNullOrEmpty(str) && File.Exists(str))
            {
                this.SafeFileDelete(str);
            }
            str = this.ServerReferenceListPath();
            if (!string.IsNullOrEmpty(str) && File.Exists(str))
            {
                this.SafeFileDelete(str);
            }
            str = this.SourceFileListPath();
            if (!string.IsNullOrEmpty(str) && File.Exists(str))
            {
                this.SafeFileDelete(str);
            }
            str = this.LinkedServerProjectsPath();
            if (!string.IsNullOrEmpty(str) && File.Exists(str))
            {
                this.SafeFileDelete(str);
            }
            this.DeleteFolderIfEmpty(this.GetHistoryFolder());
        }

        internal void DeleteFileFromVS(string fileName)
        {
            if (File.Exists(fileName))
            {
                this.SafeSetReadOnlyAttribute(fileName, false);
                this.SafeFileDelete(fileName);
                if (File.Exists(fileName))
                {
                    this.LogWarning(string.Format(CultureInfo.CurrentCulture, Resource.Failed_To_Delete_File, new object[] { fileName }));
                }
            }
        }

        protected void DeleteFolderIfEmpty(string folderPath)
        {
            if ((!string.Equals(NormalizeFolderPath(folderPath), NormalizeFolderPath(this.OutputDirectory), StringComparison.OrdinalIgnoreCase) && Directory.Exists(folderPath)) && (Directory.GetFiles(folderPath).Length == 0))
            {
                foreach (string str in Directory.GetDirectories(folderPath))
                {
                    string str2 = Path.Combine(folderPath, str);
                    this.DeleteFolderIfEmpty(str2);
                    if (Directory.Exists(str2))
                    {
                        return;
                    }
                }
                this.LogMessage(string.Format(CultureInfo.CurrentCulture, Resource.ClientCodeGen_Deleting_Orphan_Folder, new object[] { folderPath }));
                try
                {
                    Directory.Delete(folderPath);
                }
                catch (Exception exception)
                {
                    if ((!(exception is IOException) && !(exception is UnauthorizedAccessException)) && !(exception is DirectoryNotFoundException))
                    {
                        throw;
                    }
                    this.LogWarning(string.Format(CultureInfo.CurrentCulture, Resource.ClientCodeGen_Failed_Delete_Folder, new object[] { folderPath, exception.Message }));
                }
            }
        }

        public override bool Execute()
        {
            this._outputDirectory = null;
            this._clientProjectDirectory = null;
            this._filesWritten = false;
            this._errorLogged = false;
            this.NormalizeProjectPaths();
            return this.ExecuteInternal();
        }

        protected abstract bool ExecuteInternal();
        internal string FileListPath()
        {
            return Path.Combine(this.GetHistoryFolder(), this.PrependClientProjectName("RiaFiles.txt"));
        }

        protected IEnumerable<string> FilesPreviouslyWritten()
        {
            List<string> list = new List<string>();
            string str = this.FileListPath();
            if (!string.IsNullOrEmpty(str) && File.Exists(str))
            {
                using (StreamReader reader = new StreamReader(str))
                {
                    string str2;
                    if ((((str2 = reader.ReadLine()) != null) && !string.IsNullOrEmpty(str2)) && string.Equals(str2, this.ClientProjectDirectory, StringComparison.OrdinalIgnoreCase))
                    {
                        string fullPathRelativeToDirectory;
                        while ((fullPathRelativeToDirectory = reader.ReadLine()) != null)
                        {
                            if (!string.IsNullOrEmpty(fullPathRelativeToDirectory))
                            {
                                fullPathRelativeToDirectory = this.GetFullPathRelativeToDirectory(fullPathRelativeToDirectory, str2);
                                list.Add(fullPathRelativeToDirectory);
                            }
                        }
                    }
                }
            }

            return (from f in list
                    orderby Path.GetDirectoryName(f).Length descending
                    select f);
        }

        private static string FullPath(string fileName, string directory)
        {
            string path = Path.IsPathRooted(fileName) ? fileName : Path.Combine(directory, fileName);
            return Path.GetFullPath(path);
        }

        protected string GetFullPathRelativeToDirectory(string fileName, string directory)
        {
            if (!Path.IsPathRooted(fileName))
            {
                if (!Path.IsPathRooted(directory))
                {
                    directory = this.GetFullPathRelativeToDirectory(directory, this.ClientProjectDirectory);
                }
                fileName = Path.GetFullPath(Path.Combine(directory, fileName));
            }
            if (fileName.Contains(".."))
            {
                fileName = Path.GetFullPath(fileName);
            }
            return fileName;
        }

        internal string GetHistoryFolder()
        {
            return this.OutputDirectory;
        }

        internal DateTime GetLastChangeTimeFromVS(string visualStudioFile)
        {
            if (!File.Exists(visualStudioFile))
            {
                return DateTime.MinValue;
            }
            return File.GetLastWriteTime(visualStudioFile);
        }

        protected static string GetPathRelativeToProjectDirectory(string fileName, string projectDirectoryPath)
        {
            string fullPath = Path.GetFullPath(fileName);
            if (!projectDirectoryPath.EndsWith(@"\", StringComparison.OrdinalIgnoreCase))
            {
                projectDirectoryPath = projectDirectoryPath + @"\";
            }
            if (fullPath.StartsWith(projectDirectoryPath, StringComparison.OrdinalIgnoreCase))
            {
                fullPath = fullPath.Remove(0, projectDirectoryPath.Length);
            }
            return fullPath;
        }

        internal bool IsFileWriteTimeDifferent(string fileName, DateTime referenceTime)
        {
            return (!File.Exists(fileName) || (this.GetLastChangeTimeFromVS(fileName) != referenceTime));
        }

        internal bool IsFileWriteTimeDifferent(string fileName, string referenceFileName)
        {
            return (!File.Exists(referenceFileName) || this.IsFileWriteTimeDifferent(fileName, this.GetLastChangeTimeFromVS(referenceFileName)));
        }

        internal string LinkedServerProjectsPath()
        {
            return Path.Combine(this.GetHistoryFolder(), this.PrependClientProjectName("RiaLinks.txt"));
        }

        public void LogError(string message)
        {
            this.HasLoggedErrors = true;
            base.Log.LogError(message, new object[0]);
        }

        public void LogError(string message, string subcategory, string errorCode, string helpKeyword, string file, int lineNumber, int columnNumber, int endLineNumber, int endColumnNumber)
        {
            base.Log.LogError(subcategory, errorCode, helpKeyword, file, lineNumber, columnNumber, endLineNumber, endColumnNumber, message, new object[0]);
        }

        public void LogMessage(string message)
        {
            base.Log.LogMessage(message, new object[0]);
        }

        public void LogWarning(string message)
        {
            base.Log.LogWarning(message, new object[0]);
        }

        public void LogWarning(string message, string subcategory, string errorCode, string helpKeyword, string file, int lineNumber, int columnNumber, int endLineNumber, int endColumnNumber)
        {
            base.Log.LogWarning(subcategory, errorCode, helpKeyword, file, lineNumber, columnNumber, endLineNumber, endColumnNumber, message, new object[0]);
        }

        internal static string NormalizeFolderPath(string path)
        {
            if (path == null)
            {
                throw new ArgumentNullException("path");
            }
            if (path.Length > 0)
            {
                path = Path.GetFullPath(path);
                int length = path.Length;
                if ((length > 0) && (path[length - 1] == Path.DirectorySeparatorChar))
                {
                    path = path.Substring(0, length - 1);
                }
            }
            return path;
        }

        protected virtual void NormalizeProjectPaths()
        {
            if (!string.IsNullOrEmpty(this.ClientProjectPath) && !Path.IsPathRooted(this.ClientProjectPath))
            {
                this.ClientProjectPath = Path.GetFullPath(this.ClientProjectPath);
            }
            if (!string.IsNullOrEmpty(this.OutputPath) && !Path.IsPathRooted(this.OutputPath))
            {
                this.OutputPath = this.GetFullPathRelativeToDirectory(this.OutputPath, this.ClientProjectDirectory);
            }
        }

        private string PrependClientProjectName(string fileName)
        {
            return (Path.GetFileNameWithoutExtension(this.ClientProjectPath) + "." + fileName);
        }

        internal string ReadFileFromVS(string fileName)
        {
            return File.ReadAllText(fileName);
        }

        internal bool SafeFileCopy(string sourceFile, string destinationFile, bool isProjectFile)
        {
            string message = null;
            if ((!string.IsNullOrEmpty(destinationFile) && !string.IsNullOrEmpty(sourceFile)) && File.Exists(sourceFile))
            {
                this.SafeFolderCreate(Path.GetDirectoryName(destinationFile));
                if (isProjectFile)
                {
                    this.SafeSetReadOnlyAttribute(destinationFile, false);
                }
                try
                {
                    File.Copy(sourceFile, destinationFile, true);
                }
                catch (IOException exception)
                {
                    message = exception.Message;
                }
                catch (NotSupportedException exception2)
                {
                    message = exception2.Message;
                }
                catch (UnauthorizedAccessException exception3)
                {
                    message = exception3.Message;
                }
                if (message != null)
                {
                    this.LogWarning(string.Format(CultureInfo.CurrentCulture, Resource.Failed_To_Copy_File, new object[] { sourceFile, destinationFile, message }));
                }
            }
            if (isProjectFile)
            {
                this.SafeSetReadOnlyAttribute(destinationFile, true);
                this.FilesWereWritten = true;
            }
            return (message == null);
        }

        internal bool SafeFileDelete(string fileName)
        {
            string message = null;
            if (!string.IsNullOrEmpty(fileName) && File.Exists(fileName))
            {
                if (!this.SafeSetReadOnlyAttribute(fileName, false))
                {
                    return false;
                }
                try
                {
                    File.Delete(fileName);
                }
                catch (IOException exception)
                {
                    message = exception.Message;
                }
                catch (NotSupportedException exception2)
                {
                    message = exception2.Message;
                }
                catch (UnauthorizedAccessException exception3)
                {
                    message = exception3.Message;
                }
                if (message != null)
                {
                    this.LogWarning(string.Format(CultureInfo.CurrentCulture, Resource.Failed_To_Delete_File_Error, new object[] { fileName, message }));
                }
            }
            return (message == null);
        }

        internal bool SafeFileMove(string sourceFile, string destinationFile)
        {
            string message = null;
            if ((!string.IsNullOrEmpty(destinationFile) && !string.IsNullOrEmpty(sourceFile)) && File.Exists(sourceFile))
            {
                this.SafeFileDelete(destinationFile);
                try
                {
                    File.Move(sourceFile, destinationFile);
                }
                catch (IOException exception)
                {
                    message = exception.Message;
                }
                catch (NotSupportedException exception2)
                {
                    message = exception2.Message;
                }
                catch (UnauthorizedAccessException exception3)
                {
                    message = exception3.Message;
                }
                if (message != null)
                {
                    this.LogWarning(string.Format(CultureInfo.CurrentCulture, Resource.Failed_To_Rename_File, new object[] { sourceFile, destinationFile, message }));
                }
            }
            return (message == null);
        }

        internal bool SafeFileWrite(string fileName, string contents)
        {
            string message = null;
            try
            {
                File.WriteAllText(fileName, contents);
            }
            catch (IOException exception)
            {
                message = exception.Message;
            }
            catch (NotSupportedException exception2)
            {
                message = exception2.Message;
            }
            catch (UnauthorizedAccessException exception3)
            {
                message = exception3.Message;
            }
            if (message != null)
            {
                this.LogWarning(string.Format(CultureInfo.CurrentCulture, Resource.Failed_To_Write_File, new object[] { fileName, message }));
            }
            return (message == null);
        }

        internal bool SafeFolderCreate(string directoryPath)
        {
            string message = null;
            if (!string.IsNullOrEmpty(directoryPath) && !Directory.Exists(directoryPath))
            {
                try
                {
                    Directory.CreateDirectory(directoryPath);
                }
                catch (IOException exception)
                {
                    message = exception.Message;
                }
                catch (NotSupportedException exception2)
                {
                    message = exception2.Message;
                }
                catch (UnauthorizedAccessException exception3)
                {
                    message = exception3.Message;
                }
                if (message != null)
                {
                    this.LogError(string.Format(CultureInfo.CurrentCulture, Resource.Failed_To_Create_Folder, new object[] { directoryPath, message }));
                }
            }
            return (message == null);
        }

        internal bool SafeSetReadOnlyAttribute(string fileName, bool newState)
        {
            string message = null;
            if (File.Exists(fileName))
            {
                try
                {
                    FileAttributes fileAttributes = File.GetAttributes(fileName);
                    bool flag = (fileAttributes & FileAttributes.ReadOnly) != 0;
                    if (flag != newState)
                    {
                        fileAttributes ^= FileAttributes.ReadOnly;
                        File.SetAttributes(fileName, fileAttributes);
                    }
                }
                catch (IOException exception)
                {
                    message = exception.Message;
                }
                catch (NotSupportedException exception2)
                {
                    message = exception2.Message;
                }
                catch (UnauthorizedAccessException exception3)
                {
                    message = exception3.Message;
                }
                if (message != null)
                {
                    this.LogError(string.Format(CultureInfo.CurrentCulture, Resource.Failed_To_Modify_ReadOnly, new object[] { fileName, message }));
                }
            }
            return (message == null);
        }

        internal string ServerReferenceListPath()
        {
            return Path.Combine(this.GetHistoryFolder(), this.PrependClientProjectName("RiaServerRefs.txt"));
        }

        internal string SourceFileListPath()
        {
            return Path.Combine(this.GetHistoryFolder(), this.PrependClientProjectName("RiaSourceFiles.txt"));
        }

        internal bool WriteFileToVS(string destinationFile, string content, bool forceWriteToFile)
        {
            string directoryName = Path.GetDirectoryName(destinationFile);
            if (!this.SafeFolderCreate(directoryName))
            {
                return false;
            }
            if (!this.SafeSetReadOnlyAttribute(destinationFile, false))
            {
                return false;
            }
            this.SafeFileWrite(destinationFile, content);
            this.SafeSetReadOnlyAttribute(destinationFile, true);
            this.FilesWereWritten = true;
            return true;
        }

        internal bool WriteOrDeleteFileToVS(string destinationFile, string content, bool forceWriteToFile)
        {
            if (!string.IsNullOrEmpty(content))
            {
                return this.WriteFileToVS(destinationFile, content, forceWriteToFile);
            }
            if (File.Exists(destinationFile))
            {
                this.LogMessage(string.Format(CultureInfo.CurrentCulture, Resource.Deleting_Empty_File, new object[] { destinationFile }));
                this.DeleteFileFromVS(destinationFile);
            }
            return false;
        }

        protected string ClientProjectDirectory
        {
            get
            {
                if (this._clientProjectDirectory == null)
                {
                    if (this.ClientProjectPath == null)
                    {
                        this.LogError(string.Format(CultureInfo.CurrentCulture, Resource.ProjectPath_Argument_Required, new object[] { "ClientProjectPath" }));
                        return string.Empty;
                    }
                    this._clientProjectDirectory = Path.GetFullPath(Path.GetDirectoryName(this.ClientProjectPath));
                }
                return this._clientProjectDirectory;
            }
        }

        [Required]
        public string ClientProjectPath { get; set; }

        internal bool FilesWereWritten
        {
            get
            {
                return this._filesWritten;
            }
            set
            {
                this._filesWritten = value;
            }
        }

        internal string GeneratedCodePath
        {
            get
            {
                if (string.IsNullOrEmpty(this._generatedCodePath))
                {
                    this._generatedCodePath = this.GetFullPathRelativeToDirectory("Generated_Code", this.ClientProjectDirectory);
                }
                return this._generatedCodePath;
            }
            set
            {
                this._generatedCodePath = string.IsNullOrEmpty(value) ? null : (Path.IsPathRooted(value) ? value : this.GetFullPathRelativeToDirectory(value, this.ClientProjectDirectory));
            }
        }

        public bool HasLoggedErrors
        {
            get
            {
                return this._errorLogged;
            }
            protected set
            {
                this._errorLogged = value;
            }
        }

        public string LiveIntellisense { get; set; }

        protected string OutputDirectory
        {
            get
            {
                if (this._outputDirectory == null)
                {
                    string outputPath = this.OutputPath;
                    if (!Path.IsPathRooted(outputPath))
                    {
                        outputPath = Path.Combine(this.ClientProjectDirectory, outputPath);
                    }
                    this._outputDirectory = Path.GetFullPath(outputPath);
                }
                return this._outputDirectory;
            }
        }

        [Required]
        public string OutputPath { get; set; }
    }
}

